/*
 * @Author: wuqingchun
 * @Date: 2024-06-21 10:14:39
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-06-22 15:35:52
 */
#ifndef __HTTP_LOGGER_H__
#define __HTTP_LOGGER_H__

#include <stdio.h>
#include <stdint.h>

#include <thread>

#include "http.h"
#include "http_error.h"
#include "http_blockqueue.h"

// 日志级别定义
enum class ELogLevel
{
    LEVEL_DEBUG,
    LEVEL_INFO,
    LEVEL_WARN,
    LEVEL_ERROR,
};

// 日志类
class CHTTPLogger
{
private:
    static constexpr size_t PATH_MAX = 256; // 包含结束符的文件路径最大长度

    static constexpr size_t LOG_LINE_MAX = 1024; // 一行日志信息最大长度

public:
    CHTTPLogger(bool bAsync, ELogLevel enLevel, size_t ulMaxSize);
    ~CHTTPLogger();

    int32_t Init(const char* pcPath);

    void Output(ELogLevel enLevel, int32_t iErrCode, const char* pcLine, const char* pcFunc, const char* pcFmt, ...);

public:
    static void Syslog(const char *format, ...);

private:
    void __ThreadFuncAsync();

    int32_t __FormatLog(HTTP_STRING_S& refMsg, ELogLevel enLevel, int32_t iErrCode, const char* pcLine, const char* pcFunc, const char* pcFmt, va_list ap);
    void __WriteLog(HTTP_STRING_S& refMsg);

    char* __AllocBuffer();
    void __FreeBuffer(const char* pcBuff);

    int32_t __OpenLogFile();
private:
    bool          m_bAsync {false};                           // 是否使用异步日志模式
    ELogLevel     m_enLogLevel{ELogLevel::LEVEL_INFO};        // 日志级别
    volatile bool m_bThreadAsyncRunning = false;              // 异步日志线程运行标记
    std::thread   m_objThreadAsync;                           // 异步日志线程

    char          m_szPath[PATH_MAX];
    char          m_szFileName[PATH_MAX];
    FILE*         m_pstFile {nullptr};
    size_t        m_ulFileSize {0};
    size_t        m_ulMaxSize  {0};
    CHTTPBlockQueue<HTTP_STRING_S, 1024> m_objLogQueue;
};

// __STRINGIFY_INNER(x) 宏中的 #x 将 x 转换为字符串字面量，而 STRINGIFY(x) 宏用于处理可能包含宏参数的 x。
// 这是必要的，因为预处理器在展开宏时只处理一层。
#define __STRINGIFY_INNER(x) #x  
#define STRINGIFY(x) __STRINGIFY_INNER(x)  

#define LOG_POSITION __FILE__":" STRINGIFY(__LINE__) , __FUNCTION__

#define HTTP_DEBUG(fmt, ...)\
    m_refLogger.Output(ELogLevel::LEVEL_DEBUG, HTTP_OK, LOG_POSITION, fmt, ##__VA_ARGS__)

#define HTTP_INFO(fmt, ...)\
    m_refLogger.Output(ELogLevel::LEVEL_INFO, HTTP_OK, LOG_POSITION, fmt, ##__VA_ARGS__)

#define HTTP_ERROR(iErrCode, fmt, ...)\
    m_refLogger.Output(ELogLevel::LEVEL_ERROR, iErrCode, LOG_POSITION, fmt, ##__VA_ARGS__)
#endif //__HTTP_LOGGER_H__